/***************************************************************************************************
  *Copyright(C),2010-2016,Sumscope
  *FileName	:  pinyin_search_idfile.cpp
  *Author	:  scofined.qi
  *Version	:  1.0
  *Date		:  2017/06/04
  *Desc		:  //用于主要说明此程序文件完成的主要功能
  *Relation :  
  *Others	:  //其他内容说明
  *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
  *History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
***************************************************************************************************/
#include "pinyin_search_idfile.h"
#include "pinyin_search_set.h"
#include <core/strings/string_convert.h>
#include <core/system/memory.h>
#include <QTemporaryFile>
#include <QStandardPaths>
#include <QDir>

#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#endif

#ifndef BASSERTS
#define BASSERTS //
#endif
#ifndef BASSERT
#define BASSERT //
#endif
#ifndef BLOGERR
#define BLOGERR //
#endif
#ifndef BLOGINFO
#define BLOGINFO //
#endif
#ifndef BLOGDEBUG
#define BLOGDEBUG //
#endif

#define MAX_PATH 260

namespace qb{
	namespace base{
		namespace internal{
			class SingleMappingView{							// 映射视图
				int			m_size;						// 视图大小，通常都是view size的倍数
				int			m_start;					// 在文件中的偏移量,是系统PAGE_SIZE的整数倍
				char*		m_view;						// 映射好的内存，后续需要解决使用试用一个内存地址去映射
				char*		m_last;						// 上一个m_view指针,用于绑定一个内存位置,反复使用
                unsigned long m_granularity;				// 系统内存分配粒度
				u64			m_acquie_count;				// Acquire调用次数
				SingleMappingView*	m_next;
				SingleMappingView*	m_prev;
				friend class MultiMappingView;
			public:
				SingleMappingView() :m_size(0), m_start(0), m_view(0), m_last(0),
					m_granularity(64 * 1024), m_acquie_count(0), m_next(nullptr), m_prev(nullptr)
				{
                    m_granularity = qb::base::getMemPageSize();
				}
				~SingleMappingView(){ Release(); }
			protected:
				int GetCenter()const{ return m_start + m_size / 2; }
				void SetNext(SingleMappingView* next){ m_next = next; }
				void SetPrev(SingleMappingView* prev){ m_prev = prev; }
				SingleMappingView* GetNext()const{ return m_next; }
				SingleMappingView* GetPrev()const{ return m_prev; }
			public://统计用
				u64 GetAcquireCount()const{ return m_acquie_count; }
				int GetSize()const{ return m_size; }
				int GetBytes()const{ return m_view ? m_size : 0; }
			private://统计用
				bool Contains(int offset, int bytes)const
				{
					return m_view && offset >= m_start&& offset + bytes < m_start + m_size;
				}

                bool Acquire(void* mapping, int start, int size)
				{
					BASSERT(mapping != NULL);
					m_start = start;
					m_size = size;
					m_acquie_count++;
#ifdef WIN32
					if (m_last)
                        m_view = (char*)MapViewOfFileEx(mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, start, size, m_last);
					if (m_view == nullptr)
                        m_view = (char*)MapViewOfFileEx(mapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, start, size, 0);

                    if (m_view == nullptr)
                    {
                        BASSERTS(0, "start=%8d size=%d last:0x%8x, error:%d", start, size, m_last, GetLastError());
                        //BVIEW("SSMapViewOfFile failed ,error:%d", GetLastError());
                    }
#else
                    m_view = (char*)((char*)mapping+start);
#endif
					return m_view != NULL;
				}

				char* GetMemory(int offset, int bytes)
				{
					BASSERT(m_view != nullptr);
					BASSERT(offset >= m_start&&offset + bytes <= m_start + m_size);
					if (Contains(offset, bytes))
						return m_view + (offset - m_start);
					return nullptr;
				}
			public:
				void Release()
				{
					m_last = m_view;
					if (m_view != NULL)
					{
#ifdef WIN32
                        UnmapViewOfFile(m_view);
#endif
						/*MEMORY_BASIC_INFORMATION mbi;
						memset(&mbi, 0, sizeof(mbi));
						VirtualQuery(m_view, &mbi, sizeof(mbi));*/
					}
					m_view = NULL;
				}

                char* ReadMemory(void* mapping, int pagesize, int offset, int bytes)
				{
					// 从映射文件mapping中读取指定位置的内存
					// 读取到的内存只保证当时有效,下一次可能被移除
					BASSERT(mapping != NULL && pagesize%m_granularity == 0);
					if (!Contains(offset, bytes))
					{
						int index = offset / pagesize;
						int start = index*pagesize;
						int size = offset + bytes - start;
						size = ROUND_ALIGN(size, pagesize);
                        Release();
                        Acquire(mapping, start, size);
					}
					return GetMemory(offset, bytes);
				}
			};

			class MultiMappingView{//1主多附
				using MappingView=SingleMappingView;
				enum{MAX_VIEW=8};
				struct SlotInfo{
					MappingView*	head;
				};
				MappingView*	m_last_view;
				int				m_view_count;
				int				m_max_count;
				SlotInfo		m_views[MAX_VIEW];

			public:
				MultiMappingView() :m_last_view(nullptr), m_view_count(0), m_max_count(4){
					memset(m_views, 0, sizeof(SlotInfo)*MAX_VIEW);
					
				}
				~MultiMappingView()
				{
					
				}
			public:
				u64 GetAcquireCount()const{
					u64 ncount = 0;
					for (int i = 0; i < MAX_VIEW; i++)
					{
						MappingView* head = m_views[i].head;
						while (head)
						{
							ncount+=head->GetAcquireCount();
							head = head->GetNext();
						}
					}
					return ncount;
				}
				int GetSize()const{ return 0; }
				int GetBytes()const{
					int bytes = 0;
					return bytes;
				}
			public:
				void Release()
				{
					// 外界需要销毁,或者扩大映射文件
					for (int i = 0; i < MAX_VIEW; i++)
					{
						MappingView* head = m_views[i].head;
						while (head)
						{
							head->Release();
							head = head->GetNext();
						}
					}
					m_last_view = nullptr;
				}

                char* ReadMemory(void* mapping, int pagesize, int offset, int bytes)
				{
					// 1.使用上一个
					if (m_last_view && m_last_view->Contains(offset, bytes))
						return m_last_view->ReadMemory(mapping, pagesize, offset, bytes);

					// 2.通过offset找到一个
					int index = offset / pagesize;
					int slot = index%MAX_VIEW;
					MappingView* head = m_views[slot].head;
					while (head && head->Contains(offset,bytes))
					{
						if (head->Contains(offset, bytes))
						{
							m_last_view = head;
							return m_last_view->ReadMemory(mapping, pagesize, offset, bytes);
						}
						head = head->GetNext();
					}

					// 3.新建一个
					if (m_view_count < m_max_count)
					{
						MappingView* view = new MappingView();
						view->SetNext(m_views[slot].head);
						if (m_views[slot].head)
							m_views[slot].head->SetPrev(view);
						m_views[slot].head = view;

						char* mem=view->ReadMemory(mapping, pagesize, offset, bytes);

						m_view_count++;
						m_last_view = view;
						return mem;
					}

					// 4.遍历找到一个,重新映射,使用与offset距离最远的
					MappingView* found = nullptr;
					int maxdist = -1;
					int foundslot = -1;
					for (int i = 0; i < MAX_VIEW; i++)
					{
						MappingView* head = m_views[i].head;
						if (head == nullptr)
							continue;
						int dist = head->GetCenter() - offset;
						dist = dist < 0 ? (-dist) : dist;
						if (dist > maxdist)
						{
							maxdist = dist;
							found = head;
							foundslot = i;
						}
					}
					
					BASSERT(found != nullptr && found == m_views[foundslot].head);
					if (foundslot != slot)
					{
						SlotInfo& oldslot = m_views[foundslot];
						SlotInfo& newslot = m_views[slot];

						oldslot.head = found->GetNext();
						if (oldslot.head)oldslot.head->SetPrev(nullptr);

						BASSERT(found->GetPrev() == nullptr);
						found->SetNext(newslot.head);
						if (newslot.head)
							newslot.head->SetPrev(found);
						newslot.head = found;
					}
					m_last_view = found;

					char* mem = found->ReadMemory(mapping, pagesize, offset, bytes);
					return mem;
				}
			};

			IndexIdFile::IndexIdFile(int npageCount) :m_reserve_ratio(0.4f), m_align_size(256), m_cur_filesize(0), m_cur_usedsize(0),
				m_view(new MappingView)
            {
#ifdef WIN32
                m_file = NULL;
#else
                m_file = -1;
#endif
                m_mapping = NULL;
				npageCount = npageCount <= 0 ? 1 : npageCount;
                m_sys_pagesize = qb::base::getMemPageSize()*npageCount;
				BASSERT(m_sys_pagesize > 0);

				m_increase_size = ROUND_ALIGN(MEGA_BYTES * 4, MEGA_BYTES);
				if (m_increase_size%m_sys_pagesize != 0)
					m_increase_size = ROUND_ALIGN(m_increase_size, m_sys_pagesize);

                QString strFileName = QDir::tempPath() + QDir::separator() + QString("QBS");
                QTemporaryFile tmpFile(strFileName);
                tmpFile.open();
                tmpFile.close();
                m_fname = strFileName.toStdString();
				Initialize(m_fname.c_str());
			}

			IndexIdFile::~IndexIdFile()
			{
				m_view->Release();

#ifdef WIN32
				if (m_mapping != NULL)
				{
					CloseHandle(m_mapping);
					m_mapping = NULL;
				}
				if (m_file != NULL)
				{
					SetFilePointer(m_file, 0, 0, FILE_BEGIN);
					SetEndOfFile(m_file);
					CloseHandle(m_file);
				}
				DeleteFileA(m_fname.c_str());
#else
                if (m_mapping)
                {
                    munmap(m_mapping, m_cur_filesize);
                    m_mapping = NULL;
                }

                if (m_file != -1)
                {
                    if (m_file)
                    {
                        ftruncate(m_file, 0);
                    }
                    close(m_file);
                    m_file = -1;
                }

                if (!m_fname.empty())
                {
                    remove(m_fname.c_str());
                }
#endif
			}

			bool IndexIdFile::Initialize(const char* fname)
			{
#ifdef WIN32
                unsigned long fileattr = FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_WRITE_THROUGH;
				fileattr |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
				m_file = CreateFileA(fname, GENERIC_WRITE | GENERIC_READ,
					0/*FILE_SHARE_READ*/, NULL, OPEN_ALWAYS, fileattr, NULL);
				if (m_file == INVALID_HANDLE_VALUE || m_file == NULL)
				{
					BLOGERR("[SSBASE]failed to open file:%s error:%d", fname, GetLastError());
					return false;
				}
				SetFilePointer(m_file, 0, 0, FILE_BEGIN);
				SetEndOfFile(m_file);
#else
                m_file = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH | S_IWOTH);
                if (m_file == -1)
                {
                    return false;
                }

                ftruncate(m_file, 0);
#endif
				return true;
			}

			bool IndexIdFile::PrepareMapping(int maxSize)
			{
				BASSERT(maxSize%m_increase_size == 0);
				m_cur_filesize = maxSize;

                BASSERT(m_mapping == NULL);
#ifdef WIN32
                unsigned long flProtect = PAGE_READWRITE | SEC_COMMIT;
				m_mapping = CreateFileMapping(m_file, NULL, flProtect, 0, m_cur_filesize, NULL);
#else
                ftruncate(m_file, m_cur_filesize);
                m_mapping = mmap(0, m_cur_filesize, PROT_READ | PROT_WRITE, MAP_SHARED, m_file, 0);
#endif
                if (m_mapping == NULL)
                    return false;

				return true;
			}
			void IndexIdFile::FreeSpace(void* memory, int offset, int bytes)
			{
				// 映射文件不需要删除
				m_keyheads.Free(memory, offset, bytes);
			}
			void* IndexIdFile::AllocByMapping(int bytes)
			{
				//if (m_check_mapping && bytes % 2 == 0)
					//return NULL;
				//扩张映射文件
				while (m_cur_usedsize + bytes > m_cur_filesize)
				{
					m_view->Release();
#ifdef WIN32
					CloseHandle(m_mapping);
                    m_mapping = NULL;
#else
                    if (m_mapping)
                    {
                        munmap(m_mapping, m_cur_filesize);
                        m_mapping = NULL;
                    }
#endif

					if (!PrepareMapping(m_cur_filesize + m_increase_size))
					{
#ifdef WIN32
						BASSERTS(0, "PrepareMapping failed,bytes:%d offset:%d filesize:%d increase_size:%d,error:%d",
							bytes, m_cur_usedsize, m_cur_filesize, m_increase_size, ::GetLastError());
#endif
						return NULL;
					}
				}

				BASSERTS(m_cur_filesize%m_sys_pagesize == 0, "filesize:%d  pagesize:%d", m_cur_filesize, m_sys_pagesize);

				return m_view->ReadMemory(m_mapping, m_sys_pagesize, m_cur_usedsize, bytes);

				//int index = m_cur_usedsize / m_sys_pagesize;
				//int start = index*m_sys_pagesize;
				//int size = m_cur_usedsize + bytes - start;
				//size = ROUND_ALIGN(size, m_sys_pagesize);
				//BASSERTS(start >= 0 && start + size <= m_cur_filesize, "end:%8x  max:%8x", start + size, m_cur_filesize);
				//BASSERTS(start%m_sys_pagesize == 0 && size%m_sys_pagesize==0, "end:%8x  max:%8x", start + size, m_cur_filesize);
				//m_view->Release();
				//m_view->Acquire(m_mapping, start, size);
				//return m_view->GetMemory(m_cur_usedsize, bytes);



				//char* mem = (char*)m_view->GetView();
				//if (mem)
				//{
				//	mem += m_cur_usedsize - start;
				//	memset(mem, 0, bytes);
				//	return mem;
				//}
				//return NULL;
			}
			void* IndexIdFile::AllocSpace(int bytes, int& offset)
			{
				BASSERT(bytes % m_align_size == 0 && bytes > 0);
				char* mem = (char*)AllocByMapping(bytes);
				if (mem == NULL)
				{
					mem=(char*)m_keyheads.AllocHead(m_cur_usedsize, bytes);
				}
				offset = m_cur_usedsize;
				m_cur_usedsize += bytes;
				return mem;
			}

			internal::IndexIdFile::KeyHead* IndexIdFile::PrepareSpace(int offset, int bytes)
			{
				// 使得从偏移量offset开始的长度为bytes字节的内存可用
				BASSERT(offset >= 0 && bytes%m_align_size == 0 && bytes > 0 && offset + bytes <= m_cur_usedsize);
				KeyHead* head = m_keyheads.GetHead(offset, bytes);
				if (head)
					return head;

				head = (KeyHead*)m_view->ReadMemory(m_mapping, m_sys_pagesize, offset, bytes);

				//if (!m_view->Contains(offset, bytes))
				//{
				//	m_view->Release();
				//	int start = ROUND_ALIGN(offset, m_sys_pagesize);
				//	if (start > offset)start -= m_sys_pagesize;
				//	int size = offset + bytes - start;
				//	size = ROUND_ALIGN(size, m_sys_pagesize);
				//	m_view->Acquire(m_mapping, start, size);
				//}
				////BASSERT(m_view->GetView() != NULL);
				////head = (KeyHead*)(m_view->GetView() + (offset - m_view->GetStart()));
				//head = (KeyHead*)(m_view->GetMemory(offset, bytes));
				BASSERT(head && /*head->m_signature == SIGNATURE&&*/ head->m_offset == offset && head->m_bytes == bytes);
				return head;
			}
			int  IndexIdFile::GetMemoryBytes()const
			{
				int bytes = sizeof(IndexIdFile);
				bytes += m_view->GetBytes();
                bytes += m_blocks.size()*sizeof(std::map<int, Block>::value_type);
				bytes += m_fname.size();
				bytes += m_keyheads.GetMemoryBytes();
				return bytes;
			}
			void IndexIdFile::Dump()const
			{
				BLOGDEBUG("[PINYIN]view:%8d blocks:%8d keyhead:%8d  filesize:%12d  usedsize:%12d acquire:%I64d",
					m_view->GetSize(), m_blocks.size(), m_keyheads.GetSize(),
					m_cur_filesize,m_cur_usedsize,m_view->GetAcquireCount()
					);
			}
			void IndexIdFile::Update(const InverseKey& key, IndexIdRange* iirange)
			{
				// 固定头部+变长记录+适度扩展区域40%
				// 当m_memory_set为0的时候,是pinyin_search_engine.cpp中UseMappingSet为true的分支
				// 表明所有的map<int,char>数据不在内存,而是存在于映射文件中,此时相当于new map<int,char>,默认初始尺寸是16
				BASSERT(iirange );
				int nRealSize = iirange->m_memory_set ? iirange->m_memory_set->size() : 0;
				int nDefaultSize = nRealSize <= 0 ? 16 : nRealSize;
				int bytes = sizeof(KeyHead) + (int)nDefaultSize*sizeof(IndexId)*(1 + m_reserve_ratio);
				bytes = ROUND_ALIGN(bytes, m_align_size);
				int offset = 0;
				void* memory = AllocSpace(bytes, offset);
				if (memory==NULL)
				{
					BLOGERR("[SSBASE]AllocSpace(%d,%d) failed,keyheads:%d", bytes, offset, m_keyheads.GetSize());
					return;
				}

				KeyHead* head = (KeyHead*)memory;
				head->m_offset = offset;
				head->m_signature = SIGNATURE;
				head->m_length = nRealSize;
				head->m_used = head->m_length*sizeof(IndexId);
				head->m_bytes = bytes;
				head->m_capcity = (bytes - sizeof(KeyHead)) / sizeof(IndexId);
				memcpy(head->m_key, key.code, sizeof(key));

				if (iirange->m_memory_set)
				{
					IndexIdVec iivec((IndexId*)(head + 1), iirange->m_memory_set->size(), head->m_capcity);
					iivec.copyfrom(*iirange->m_memory_set);
				}
				
				//m_blocks[head->m_offset] = Block(head->m_bytes, true);
				iirange->m_bytes = head->m_bytes;
				iirange->m_offset = head->m_offset;
				iirange->m_length = head->m_length;
			}

			bool IndexIdFile::AddKey(IndexIdRange* iirange, int key)
			{
				BASSERT(iirange && iirange->m_bytes>0 && iirange->m_offset >= 0 && key >= 0);
				void* memory = PrepareSpace(iirange->m_offset, iirange->m_bytes);
				if (memory == NULL)
				{
					BLOGERR("[SSBASE]PrepareSpace(%d,%d) failed", iirange->m_offset, iirange->m_bytes);
					return false;
				}
				KeyHead* head = (KeyHead*)memory;
				BASSERT(head->m_signature == SIGNATURE&& head->m_offset == iirange->m_offset && head->m_bytes % m_align_size == 0);
				IndexIdVec iivec((IndexId*)(head + 1), head->m_length, head->m_capcity);
				if (!iivec.add(key))
				{
					FreeSpace(memory, iirange->m_offset, iirange->m_bytes);
					BASSERT(head->m_length >= head->m_capcity);
					int bytes = head->m_bytes + (head->m_bytes >> 1);
					bytes = ROUND_ALIGN(bytes, m_align_size);
					int offset = 0;
					KeyHead oldhead = *head;
					void* temp = new char[oldhead.m_bytes];
					memcpy(temp, memory, oldhead.m_bytes);
					void* newmemory = AllocSpace(bytes, offset);
					if (newmemory == NULL)
					{
						BLOGERR("[SSBASE]AllocSpace(%d,%d) failed,keyheads:%d",bytes,offset,m_keyheads.GetSize());
						return false;
					}
					memcpy(newmemory, temp, oldhead.m_bytes);
					delete[] temp;
					//m_blocks[oldhead.m_offset] = Block(oldhead.m_bytes, false);

					head = (KeyHead*)newmemory;
					head->m_offset = offset;
					head->m_signature = SIGNATURE;					
					head->m_bytes = bytes;
					head->m_capcity = (head->m_bytes - sizeof(KeyHead)) / sizeof(IndexId);
					iivec.bind((IndexId*)(head + 1), head->m_length, head->m_capcity);
					bool badd=iivec.add(key);
					BASSERT(badd);
					//m_blocks[head->m_offset] = Block(head->m_bytes, true);
				}
				head->m_length = iivec.size();
				head->m_used = head->m_length*sizeof(IndexId);
				iirange->m_offset = head->m_offset;
				iirange->m_bytes = head->m_bytes;
				iirange->m_length = iivec.size();
				BASSERT(head->m_used <= head->m_bytes && head->m_length <= head->m_capcity);
				return true;
			}

			bool IndexIdFile::RemoveKey(IndexIdRange* iirange, int key)
			{
				BASSERT(iirange && iirange->m_bytes>0 && key >= 0);
				void* memory = PrepareSpace(iirange->m_offset, iirange->m_bytes);
				if (memory == NULL)
				{
					BLOGERR("[SSBASE]PrepareSpace(%d,%d) failed", iirange->m_offset, iirange->m_bytes);
					return false;
				}
				KeyHead* head = (KeyHead*)memory;
				BASSERT(head->m_signature == SIGNATURE&& head->m_offset == iirange->m_offset && head->m_bytes % m_align_size == 0);
				IndexIdVec iivec((IndexId*)(head + 1), head->m_length, head->m_capcity);
				iivec.remove(key);
				head->m_length = iivec.size();
				head->m_used = head->m_length*sizeof(IndexId);
				iirange->m_length = iivec.size();
				BASSERT(head->m_used <= head->m_bytes && head->m_length <= head->m_capcity);
				return true;
			}

			bool IndexIdFile::GetIndexIdVec(const IndexIdRange* iirange, IndexIdVec& iivec)
			{
				BASSERT(iirange && iirange->m_bytes>0 && iirange->m_length>=0);
				void* memory = PrepareSpace(iirange->m_offset, iirange->m_bytes);
				if (memory == NULL)
				{
					BLOGERR("[SSBASE]PrepareSpace(%d,%d) failed", iirange->m_offset, iirange->m_bytes);
					return false;
				}
				KeyHead* head = (KeyHead*)memory;
				BASSERT(head->m_offset == iirange->m_offset && head->m_bytes % m_align_size == 0);
				BASSERT(head->m_length == iirange->m_length && head->m_bytes == iirange->m_bytes && iirange->m_offset == head->m_offset);
				iivec.bind((IndexId*)(head + 1), head->m_length, head->m_capcity);
				return true;
			}

			IndexIdFile::KeyHeadMemory::~KeyHeadMemory()
			{
				for (BackupMemory::iterator it = m_memory.begin(); it != m_memory.end(); ++it)
				{
					KeyHead* head = it->second;
					if (head)
					{
						delete[]((char*)head);
					}
				}
				m_memory.clear();
			}

			bool IndexIdFile::KeyHeadMemory::Free(void* memory, int offset, int bytes)
			{
				if (m_memory.empty())
					return false;
				BackupMemory::iterator it = m_memory.find(memory);
				if (it != m_memory.end())
				{
					OffsetMap::iterator oit = m_offsets.find(offset);
					KeyHead* ohead = oit != m_offsets.end() ? (oit->second) : NULL;
					KeyHead* head = it->second;
					BASSERT(ohead == head);
					if (head)
					{
						BASSERT(head->m_offset == offset);
						BASSERT(head->m_bytes == bytes);
						BASSERT(head->m_signature == SIGNATURE);
						char* ptr = (char*)(it->second);
						delete[] ptr;
					}
					m_memory.erase(it);
					if (ohead)
						m_offsets.erase(oit);
					return true;
				}
				return false;
			}

            qb::base::internal::IndexIdFile::KeyHead* IndexIdFile::KeyHeadMemory::GetHead(int offset, int bytes)
			{
				if (m_offsets.empty())
					return NULL;
				OffsetMap::iterator it = m_offsets.find(offset);
				KeyHead* head = it != m_offsets.end() ? (it->second) : NULL;
				if (head)
				{
					BASSERT(head->m_bytes == bytes);
					BASSERT(head->m_signature == SIGNATURE);
				}
				return head;
			}

            qb::base::internal::IndexIdFile::KeyHead* IndexIdFile::KeyHeadMemory::AllocHead(int offset, int bytes)
			{
				if (bytes <= sizeof(KeyHead))
					return NULL;
				char* buf = new char[bytes];
				memset(buf, 0, bytes);
				KeyHead* head = (KeyHead*)buf;
				head->m_offset = offset;
				head->m_signature = SIGNATURE;
				head->m_bytes = bytes;
				m_memory[buf] = head;
				m_offsets[offset] = head;
				BASSERT(m_offsets.size() == m_memory.size());
				return head;
			}
			int IndexIdFile::KeyHeadMemory::GetMemoryBytes()const
			{
				int bytes = m_memory.size()*sizeof(BackupMemory::value_type);
				bytes += m_offsets.size()*sizeof(OffsetMap::value_type);
				for (BackupMemory::const_iterator it = m_memory.begin(); it != m_memory.end();++it)
				{
					const KeyHead* phead = it->second;
					if (phead)bytes += phead->m_bytes;
				}
				return bytes;
			}


		}
	}
}
